﻿/*
 需要屏蔽什么级别的log只需要把对应的  注释掉的Conditional代码打开即可
 */
using System.Diagnostics;
using System.Text;
using Debug = UnityEngine.Debug;
#if UNITY_EDITOR  
using System.Reflection;
using UnityEditor;
using UnityEditor.Callbacks;
#endif

public class MDebug
{
#if !OPEN_LOG
    [Conditional("SHOW_LOG")]
#endif
    public static void Log(object msg)
    {
        Debug.Log(msg);
    }
#if !OPEN_LOG
    [Conditional("SHOW_LOG")]
#endif
    public static void Log(object tag,object msg)
    {
        Debug.Log(string.Format("[{0}] {1}", tag, msg));
    }
#if !OPEN_LOG
    [Conditional("SHOW_WARNING")]
#endif
    public static void LogWarning(object msg)
    {
        Debug.LogWarning(msg);
    }

    //[Conditional("SHOW_ERROR")]
    public static void LogError(object msg)
    {
        Debug.LogError(msg);
    }

    private static StringBuilder _stringBuilder = null;
    private static bool _beginRecordLog = false;
    private static string _separator;

#if !OPEN_LOG
    [Conditional("SHOW_LOG")]
#endif
    public static void BeginRecordLog(string tip,string separator = " ")
    {
        if (_beginRecordLog)
        {
            LogWarning("BeginRecordLog Can Not Be Call Twice Before ShowRecordLog");
            return;
        }
        if (_stringBuilder == null)
        {
            _stringBuilder = new StringBuilder();
        }
        _separator = separator;
        _stringBuilder.Length = 0;
        _stringBuilder.Append(tip);
        _beginRecordLog = true;
    }
#if !OPEN_LOG
    [Conditional("SHOW_LOG")]
#endif
    public static void AppendRecordLog(object msg)
    {
        _stringBuilder.Append(msg);
        _stringBuilder.Append(_separator);
    }
#if !OPEN_LOG
    [Conditional("SHOW_LOG")]
#endif
    public static void EndRecordLogToShow()
    {
        Log(_stringBuilder.ToString());
        _stringBuilder.Remove(0, _stringBuilder.Length);
        _beginRecordLog = false;
    }

#if UNITY_EDITOR
    private static int s_InstanceID;
    static MDebug()
    {
        s_InstanceID = AssetDatabase.LoadAssetAtPath<MonoScript>("Assets/Scripts/Extend/MDebug.cs").GetInstanceID();
    }

    [UnityEditor.Callbacks.OnOpenAssetAttribute(0)]
    public static bool OnOpenAsset(int instanceID, int line)
    {
        if (instanceID == s_InstanceID)
        {
            string str = GetLogText();
            if (str == null)
            {
                return false;
            }
            int index = str.IndexOf("(at ", str.IndexOf("MDebug.cs")) + 4;
            string str2 = str.Substring(index);
            str2 = str2.Substring(0, str2.IndexOf(')'));
            string[] path = str2.Split(':');
            AssetDatabase.OpenAsset(AssetDatabase.LoadAssetAtPath<MonoScript>(path[0]), int.Parse(path[1]));
            return true;
        }
        return false;
    }

    static string GetLogText()
    {
        // 找到UnityEditor.EditorWindow的assembly
        var assembly_unity_editor = Assembly.GetAssembly(typeof(UnityEditor.EditorWindow));
        if (assembly_unity_editor == null)
            return null;

        // 找到类UnityEditor.ConsoleWindow
        var type_console_window = assembly_unity_editor.GetType("UnityEditor.ConsoleWindow");
        if (type_console_window == null)
            return null;
        // 找到UnityEditor.ConsoleWindow中的成员ms_ConsoleWindow
        var field_console_window = type_console_window.GetField("ms_ConsoleWindow", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
        if (field_console_window == null)
            return null;
        // 获取ms_ConsoleWindow的值
        var instance_console_window = field_console_window.GetValue(null);
        if (instance_console_window == null)
            return null;

        // 如果console窗口时焦点窗口的话，获取stacktrace
        if ((object)UnityEditor.EditorWindow.focusedWindow == instance_console_window)
        {
            // 通过assembly获取类ListViewState
            var type_list_view_state = assembly_unity_editor.GetType("UnityEditor.ListViewState");
            if (type_list_view_state == null)
                return null;

            // 找到类UnityEditor.ConsoleWindow中的成员m_ListView
            var field_list_view = type_console_window.GetField("m_ListView", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            if (field_list_view == null)
                return null;

            // 获取m_ListView的值
            var value_list_view = field_list_view.GetValue(instance_console_window);
            if (value_list_view == null)
                return null;

            // 下面是stacktrace中一些可能有用的数据、函数和使用方法，这里就不一一说明了，我们这里暂时还用不到
            /*
            var field_row = type_list_view_state.GetField("row", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            if (field_row == null) return null;

            var field_total_rows = type_list_view_state.GetField("totalRows", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            if (field_total_rows == null) return null;

            var type_log_entries = assembly_unity_editor.GetType("UnityEditorInternal.LogEntries");
            if (type_log_entries == null) return null;

            var method_get_entry = type_log_entries.GetMethod("GetEntryInternal", BindingFlags.Static | BindingFlags.Public);
            if (method_get_entry == null) return null;

            var type_log_entry = assembly_unity_editor.GetType("UnityEditorInternal.LogEntry");
            if (type_log_entry == null) return null;

            var field_instance_id = type_log_entry.GetField("instanceID", BindingFlags.Instance | BindingFlags.Public);
            if (field_instance_id == null) return null;

            var field_line = type_log_entry.GetField("line", BindingFlags.Instance | BindingFlags.Public);
            if (field_line == null) return null;

            var field_condition = type_log_entry.GetField("condition", BindingFlags.Instance | BindingFlags.Public);
            if (field_condition == null) return null;

            object instance_log_entry = Activator.CreateInstance(type_log_entry);
            int value_row = (int)field_row.GetValue(value_list_view);
            int value_total_rows = (int)field_total_rows.GetValue(value_list_view);
            int log_by_this_count = 0;
            for (int i = value_total_rows – 1; i > value_row; i–) {
            method_get_entry.Invoke(null, new object[] { i, instance_log_entry });
            string value_condition = field_condition.GetValue(instance_log_entry) as string;
            if (value_condition.Contains("[SDebug]")) {
            log_by_this_count++;
            }
            }
            */

            // 找到类UnityEditor.ConsoleWindow中的成员m_ActiveText
            var field_active_text = type_console_window.GetField("m_ActiveText", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            if (field_active_text == null)
                return null;

            // 获得m_ActiveText的值，就是我们需要的stacktrace
            string value_active_text = field_active_text.GetValue(instance_console_window).ToString();
            return value_active_text;
        }
        return null;
    }
#endif
}
